Skip to content

Sidebar adjustments - #36

Merged
iSiRaH merged 5 commits into
mainfrom
sidebar-adjustments
Mar 12, 2026
Merged

Sidebar adjustments#36
iSiRaH merged 5 commits into
mainfrom
sidebar-adjustments

Conversation

@JinethBosilu

Copy link
Copy Markdown
Collaborator

No description provided.

Copilot AI review requested due to automatic review settings March 12, 2026 19:05

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds criminal record CRUD functionality with Supabase photo storage, face embedding generation, and expanded criminal profile fields (crime history, address, contacts, DOB, gender, alias).

Changes:

  • New CriminalController and CriminalService for full CRUD on criminal records with photo upload to Supabase and ML embedding generation
  • New SupabaseStorageService for uploading/deleting files in Supabase Storage
  • Extended Criminal entity, FacialRecognitionService, and SecurityConfig with additional fields and role-based access

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
CriminalController.java New REST controller for criminal CRUD endpoints
CriminalService.java New service orchestrating DB ops, storage uploads, and embeddings
SupabaseStorageService.java New service for Supabase Storage file upload/delete
Criminal.java Added new profile fields (riskLevel, crimeHistory, photoUrl, DOB, gender, alias)
CriminalRepository.java Added native query for IDs with face embeddings
FacialRecognitionService.java Added generateEmbedding method; expanded registerCriminal params; renamed photophotos
FacialRecognitionController.java Extended registration endpoint with additional profile params
SecurityConfig.java Added role-based access for new criminal and facial endpoints
application.properties Added supabase.bucket config property

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment on lines +61 to +62
.requestMatchers("/api/criminals/**").hasAnyRole("Investigator", "OIC")
.requestMatchers("/api/criminals").hasAnyRole("Investigator", "OIC")

Copilot AI Mar 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Security rule ordering issue: /api/criminals/** is matched before /api/criminals due to Spring Security's first-match-wins behavior with requestMatchers. However, the more significant problem is that /api/criminals/** won't match the bare /api/criminals path (no trailing slash). The rules should be reordered so /api/criminals comes before /api/criminals/**, though in practice both have the same role set here so the functional impact is limited. Still, swap the order for correctness and consistency.

Suggested change
.requestMatchers("/api/criminals/**").hasAnyRole("Investigator", "OIC")
.requestMatchers("/api/criminals").hasAnyRole("Investigator", "OIC")
.requestMatchers("/api/criminals").hasAnyRole("Investigator", "OIC")
.requestMatchers("/api/criminals/**").hasAnyRole("Investigator", "OIC")

Copilot uses AI. Check for mistakes.
Comment on lines +34 to +35
private final RestTemplate restTemplate = new RestTemplate();

Copilot AI Mar 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This creates a new RestTemplate instance directly instead of using the Spring-managed RestTemplate bean (configured with timeouts in RestTemplateConfig). This means uploads will use default infinite timeouts, which could cause threads to hang indefinitely if Supabase is unresponsive. Inject the existing RestTemplate bean via constructor injection instead.

Suggested change
private final RestTemplate restTemplate = new RestTemplate();
private final RestTemplate restTemplate;
public SupabaseStorageService(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}

Copilot uses AI. Check for mistakes.
listHeaders.set("apikey", supabaseServiceKey);
listHeaders.setContentType(MediaType.APPLICATION_JSON);

String listBody = "{\"prefix\":\"" + criminalId + "/\",\"limit\":100}";

Copilot AI Mar 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The criminalId is concatenated directly into the JSON string without escaping. If criminalId contains characters like " or \, this will produce malformed JSON or could be exploited for JSON injection. Use the ObjectMapper to serialize the body safely, as is done later in the method for deleteBody.

Copilot uses AI. Check for mistakes.
Comment on lines +51 to +53
String storagePath = criminalId + "/" + safeFilename;

String uploadUrl = supabaseUrl + "/storage/v1/object/" + bucket + "/" + storagePath;

Copilot AI Mar 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The criminalId is interpolated directly into URL paths without encoding. If the ID contains special characters (e.g., /, %, ?), it could break the URL or lead to path traversal. Although currently generated as a UUID substring (safe), the uploadPhoto method accepts an arbitrary String. Consider URL-encoding the path segments.

Copilot uses AI. Check for mistakes.
Comment on lines +132 to +145
String deleteUrl = supabaseUrl + "/storage/v1/object/" + bucket;

HttpHeaders deleteHeaders = new HttpHeaders();
deleteHeaders.set("Authorization", "Bearer " + supabaseServiceKey);
deleteHeaders.set("apikey", supabaseServiceKey);
deleteHeaders.setContentType(MediaType.APPLICATION_JSON);

String deleteBody = mapper.writeValueAsString(new java.util.LinkedHashMap<String, Object>() {{
put("prefixes", prefixes);
}});
HttpEntity<String> deleteRequest = new HttpEntity<>(deleteBody, deleteHeaders);

ResponseEntity<String> deleteResponse = restTemplate.exchange(
deleteUrl, HttpMethod.DELETE, deleteRequest, String.class);

Copilot AI Mar 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Supabase bulk delete endpoint is POST /storage/v1/object/remove/{bucket}, not DELETE /storage/v1/object/{bucket}. The current URL and HTTP method appear incorrect — this will likely result in a 404 or 405 from Supabase. The URL should be supabaseUrl + "/storage/v1/object/remove/" + bucket and the method should be HttpMethod.POST (or HttpMethod.DELETE with the correct path, depending on the Supabase API version).

Copilot uses AI. Check for mistakes.
.requestMatchers("/api/facial/criminals").hasAnyRole("Investigator", "OIC")
.requestMatchers("/api/facial/**").hasRole("Investigator")

// Criminal CRUD (direct DB, no Python)

Copilot AI Mar 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment says "Criminal CRUD (direct DB, no Python)" but CriminalService.createCriminal and updateCriminal both call facialRecognitionService.generateEmbedding(), which forwards to the Python ML service. The comment is misleading.

Suggested change
// Criminal CRUD (direct DB, no Python)
// Criminal CRUD endpoints

Copilot uses AI. Check for mistakes.
@iSiRaH
iSiRaH merged commit 8bc5461 into main Mar 12, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants